home *** CD-ROM | disk | FTP | other *** search
- // SpaceHack.c
- //
- // A sample that shows how to do the equivalent of the "space hack"
- // under QuickDraw GX, since that hack no longer works (and this
- // new method isn't a hack).
- //
- // The "Space Hack" is the technique of printing a single space (' ')
- // in a font in order to get that font resident on a printer so you
- // can use it directly from PostScript.
- //
- // Under QuickDraw GX, printing a space gets a font that consists solely
- // of a space on the printer, which isn't exactly what you wanted.
- //
- // The function FontToPict() is something you can drop into an app
- // which uses this technique. It checks for the presence of QuickDraw
- // GX, and calls the correct code. In the QuickDraw GX case, it calls
- // makePSHandle, which makes, surprisingly enough, a handle full of
- // PS (PostScript), which you can send to the printer by embedding it
- // in a PicComment, and calling DrawPicture on the resulting picture.
- //
- // MakePSHandle() builds an encoding array (if one isn't passed to it),
- // calls GXFlattenFont (via a wrapper function, FontToHandle), and
- // cleans up any messes.
-
- #include <Memory.h>
- #include <QuickDraw.h>
- #include <Script.h>
- #include <ToolUtils.h>
- #include <GXFonts.h>
- #include <GXGraphics.h>
- #include <GXEnvironment.h>
- #include <Files.h>
- #include <Fonts.h>
- #include <StandardFile.h>
- #include <Gestalt.h>
- #include <Resources.h>
-
- #include "exceptions.h"
-
- typedef struct {
- gxSpoolBlock spool;
- long reference;
- long position;
- long size;
- void *data;
- void *userField;
- } userSpool;
-
- #define allocationIncrement 128
-
- #define gestaltGXVersion 'qdgx' // in PrintingManager.h (old) or GXPrinting.h (new)
- #define gestaltGXPrintingMgrVersion 'pmgr' // in PrintingManager.h (old) or GXPrinting.h (new)
-
- // our entrypoints
- PicHandle FontToPict(short qdFont, short qdStyle); // returns a PICT suitable for printing
- OSErr MakePSHandle(short qdFont, char qdStyle, unsigned short *encodingArray, Handle *encHandle);
-
- // utility functions
- static Handle FontToHandle(gxFont fontID, unsigned short encoding[]);
- static long MakeMac8BitEncoding(gxFont theFont, unsigned short encoding[]);
- static gxFont ConvertQDFontToGXFont(short qdFont, short qdStyle);
- static void GetPostScriptFontName(gxFont fontID, Str255 fontName);
- static Boolean GXInstalled(void);
- static void InitToolbox(void);
- static void DumpHandleToFile(PicHandle data);
-
-
-
-
-
-
-
- void main(void)
- {
- PicHandle picture;
- short testFontRef = 0; // put real font reference here
- InitToolbox();
-
- picture = FontToPict(testFontRef, 0);
- DumpHandleToFile(picture);
- }
-
-
-
-
- // return a pict that can be printed via DrawPicture
- // NOTE: You'd better have your grafPort setup before
- // calling this, or it'll blast the windowManager port
- PicHandle FontToPict(short qdFont, short qdStyle)
- {
- Rect theRect = {0, 0, 1, 1};
- PicHandle thePict = OpenPicture(&theRect);
- const short kPostScriptHandle = 192;
-
- if (GXInstalled()) { // If QuickDraw GX is present, use the new method
- Handle piccommentHdl;
- // The following pointer would typically be set to an array
- // of the characters you're going to use. For test purposes
- // we're passing a nil, which say "Give me the whole font."
- // actually specifying the encoding becomes critical for CJK
- // fonts, since sending the whole umpty-thousand characters
- // would be bad (Don't cross the beams!)
- unsigned short *myEncoding = nil;
-
- MakePSHandle(qdFont,qdStyle,myEncoding,&piccommentHdl);
- PicComment(kPostScriptHandle,GetHandleSize(piccommentHdl),piccommentHdl);
- } else { // if we don't have QuickDraw GX, use the old method
- Point penPoint;
-
- // we would normally set the clip here, but since we're just
- // drawing a space, there's not really a need
- GetPen(&penPoint); // save the pen location
- TextFont(qdFont);
- TextFace(qdStyle);
- DrawChar(' ');
- MoveTo(penPoint.h,penPoint.v); // restore the pen location
- }
-
- ClosePicture();
- return(thePict);
- }
-
-
-
-
-
-
- /**************************************************
- Make a handle full of postscript font
- ***************************************************/
- OSErr MakePSHandle(short qdFont, char qdStyle, unsigned short *encodingArray, Handle *outputHandle)
- {
- OSErr status = noErr;
- gxFont theFont;
- unsigned short *myEncoding;
- Boolean madeEncoding = false;
-
- theFont = ConvertQDFontToGXFont(qdFont,qdStyle); // convert to a gxFont
-
- if (!encodingArray) {
- long returnLength;
-
- myEncoding = (unsigned short *)NewPtrClear(256 * sizeof(short));
- returnLength = MakeMac8BitEncoding(theFont, myEncoding);
- if (returnLength != 256) {
- DebugStr("\pHmm. We didn't get a full encoding.");
- return(returnLength); // pass the error along
- }
- madeEncoding = true;
- } else {
- myEncoding = encodingArray;
- }
-
- *outputHandle = FontToHandle(theFont, myEncoding);
-
- if (madeEncoding) DisposePtr((Ptr)myEncoding);
-
- status = MemError();
- if (status == noErr) {
- status = GXGetGraphicsError(nil);
- if (status != noErr) {
- DisposeHandle(*outputHandle);
- *outputHandle = nil;
- }
- }
- return(status);
- }
-
-
-
-
-
-
- //
- // Utility functions
- //
- static Boolean GXInstalled(void)
- {
- long version;
-
- if (Gestalt(gestaltGXVersion, &version) == noErr)
- if (Gestalt(gestaltGXPrintingMgrVersion, &version) == noErr)
- return(true);
- return(false);
- }
-
- // get the postScript unique name of the font. Return a C String.
- static void GetPostScriptFontName(gxFont fontID, Str255 fontName)
- {
- long length;
- length = GXFindFontName(fontID, gxPostscriptFontName, gxNoPlatform,
- gxNoScript, gxNoLanguage, fontName, nil);
-
- // the PostScript name shouldn't ever be more than 255 characters
- // long, but if it is, something has gone horribly awry. Best to
- // at least detect the error, rather than let it propagate and
- // trash something else.
- if (length > 255) DebugStr("\pOOPS. We're dead in the water.");
- else fontName[length]=0; // string isn't terminated, so we do it
- }
-
- static long HandleSpoolProc(gxSpoolCommand command, userSpool *block)
- {
- OSErr status = noErr;
-
- switch (command) {
- case gxOpenReadSpool:
- block->size = 0;
- block->position = 0;
- break;
- case gxOpenWriteSpool:
- block->data = NewHandle(allocationIncrement);
- block->size = allocationIncrement;
- block->position = 0;
- status = MemError();
- break;
- case gxReadSpool:
- BlockMove((*(char **) block->data) + block->position,
- block->spool.buffer,
- block->spool.count);
- block->position += block->spool.count;
- break;
- case gxWriteSpool:
- {
- register long oldPosition;
-
- oldPosition = block->position;
- block->position += block->spool.count;
-
- /* make sure there's room for one buffer past current pointer */
- if (block->position + block->spool.bufferSize > block->size) {
- block->size += block->spool.bufferSize;
- HUnlock((Handle) block->data);
- SetHandleSize((Handle) block->data, block->size);
- HLock((Handle) block->data);
- status = MemError();
- }
- if (status == noErr)
- BlockMove(block->spool.buffer,
- (*(char **) block->data + oldPosition),
- block->spool.count);
- }
- break;
- case gxCloseSpool:
- SetHandleSize((Handle) block->data, block->position);
- status = MemError();
- break;
- }
- return(status);
- }
-
- /***********************
- Wrapper for call to GXFlattenFont to make it easier
-
- fontID: the gxFont reference to use for making the encoding.
- encoding: The array of glyph codes indicating order
- and id's of glyphs to make encoding for.
- *************/
- static Handle FontToHandle(gxFont fontID, unsigned short encoding[256])
- {
- userSpool block;
- scalerStream stream;
- Str255 fontName;
-
- block.spool.spoolProcedure = NewgxSpoolProc(HandleSpoolProc);
- block.spool.buffer = nil;
- block.spool.bufferSize = 0;
-
- stream.streamRefCon = fontID;
- stream.types = type1StreamType;
- #if JUST_ENCODING
- // Have font scaler make just an encoding for us
- stream.action = encodingOnlyStreamAction;
- #else
- // Get a downloadable font
- stream.action = downloadStreamAction;
- #endif
- stream.memorySize = 0;
- stream.variationCount = selectAllVariations;
- stream.variations = nil;
- stream.info.font.encoding = encoding;
- stream.info.font.glyphBits = nil;
-
- GetPostScriptFontName(fontID,fontName);
-
- stream.info.font.name = (char *)fontName; // this should NOT be a pString
-
- // Call the scaler to generate the data for us.
- GXFlattenFont(fontID, &stream, &block.spool);
-
- DisposeRoutineDescriptor(block.spool.spoolProcedure);
- return (Handle) block.data;
- }
-
-
- /*******************************************************
- Function: MakeMac8BitEncoding:
-
- Function sets up an encoding vector for the standard
- Mac 8 bit encoding for the current active script system.
-
- theFont: the font to make encoding for.
- encoding: array of 256 shorts, encoding will be returned
- in here.
- returns: The number of bytes encoded. (should always be 256)
- ********************************************************/
- static long MakeMac8BitEncoding(gxFont theFont, unsigned short encoding[])
- {
- gxFontScript theScript;
- long index;
- unsigned char theBytes[256];
- long length;
- short i;
-
- theScript = (gxFontScript)GetEnvirons(smSysScript) + 1; // Quickdraw GX scripts are 1+scriptmgr scripts.
-
- // try system script first
- index = GXFindFontEncoding(theFont, gxMacintoshPlatform, theScript, gxNoLanguage);
- if(!index) {
- // well, that didn't work. Try roman
- index = GXFindFontEncoding(theFont, gxMacintoshPlatform, gxRomanScript, gxNoLanguage);
- }
-
- /** Make the mac character set **/
- for (i = 0; i < 256; ++i)
- theBytes[i] = i;
-
- /** Convert it to glyph codes **/
- length = GXApplyFontEncoding(theFont, index, nil, theBytes, 256, encoding, nil);
-
- return(length);
- }
-
- static gxFont ConvertQDFontToGXFont(short qdFont, short qdStyle)
- {
- gxFont theFont;
- gxStyle theStyle = GXNewStyle();
- GXConvertQDFont(theStyle, qdFont, qdStyle);
- theFont = GXGetStyleFont(theStyle);
- GXDisposeStyle(theStyle);
- return(theFont);
- }
-
- static void DumpHandleToFile(PicHandle data)
- {
- StandardFileReply reply;
- Str255 defaultName = "\pFontDump";
- Str255 prompt = "\pCreate font file";
- short fref;
-
- if (!data) return;
-
- StandardPutFile(prompt,defaultName,&reply);
- if (reply.sfGood) {
- if (reply.sfReplacing) FSpDelete(&(reply.sfFile));
- FSpCreateResFile(&(reply.sfFile),'RSED','rsrc',reply.sfScript);
- fref = FSpOpenResFile(&(reply.sfFile),fsRdWrPerm);
- AddResource((Handle)data,'PICT',1,"\ptest picture");
- UpdateResFile(fref);
- CloseResFile(fref);
- }
- }
-
- static void InitToolbox(void)
- {
- Handle myMenuBar;
- MenuHandle appleMenu;
-
- InitGraf( &qd.thePort );
- InitFonts();
- FlushEvents( everyEvent, 0 );
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs( nil );
- InitCursor();
-
- // this little demo doesn't use the menu bar, but hey
- myMenuBar = GetNewMBar( 128 );
- SetMenuBar( myMenuBar );
- appleMenu = GetMHandle( 128 );
-
- AddResMenu( appleMenu, 'DRVR' );
- DrawMenuBar();
- }
-